#ifndef PORT_HW_H
#define PORT_HW_H

/******************************************************************
| includes
| 1) system and project includes
| 2) needed interfaces from external units
| 3) internal and external interfaces from this unit
|-----------------------------------------------------------------*/

#include "Reg_Port.h"
#include "Port_Cfg.h"
#include "Port_Types.h"

/*******************************************************************
| defines and macros (scope: module-local)
|------------------------------------------------------------------*/

/**  brief GET_PIN_INDEX(PinId) macro: get the hardware pin index of user PinId
 **/
#define GET_PIN_INDEX(PinId)			((PinId) & 0x0F)

/**  brief GET_PIN_INDEX(PinId) macro: get the hardware port index of user PinId
 **/
#define GET_PORT_INDEX(PinId)			(PortPinIdType)(((PinId) & 0xF0) >> 4)

/**  brief CLEAR_PORT_PIN_DYN_STATUS(PinIdx) macro: clear the dynamic status of pin specified by PinIdx
 **/
#define CLEAR_PORT_PIN_DYN_STATUS(PinIdx)		(PinDynStatusTbl[(PinIdx)] ^= PinDynStatusTbl[(PinIdx)])

/**  brief PORT_PIN_DYN_DIR_MASK macro: the mask flag of the direction status of a pin
 ** 		bit 0 of PinDynStatusTbl[?]
 ** 		value 0: input
 ** 		value 1: output
 **/
#define PORT_PIN_DYN_DIR_MASK			0x00000001UL

/**  brief PORT_PIN_DYN_DIR_OUT macro: the status flag of the output direction of a pin
 **/
#define PORT_PIN_DYN_DIR_OUT			0x00000001UL

/**  brief PORT_PIN_DYN_DIR_IN macro: the status flag of the input direction of a pin
 **/
#define PORT_PIN_DYN_DIR_IN				0x00000000UL

/**  brief CHECK_PORT_PIN_DYNDIR_OUT(PinIdx) macro:
 **		check if the direction of the pin specified by PinIdx is output
 **		value TRUE: output
 **		value FALSE: input
 **/
#define CHECK_PORT_PIN_DYNDIR_OUT(PinIdx)	((PinDynStatusTbl[(PinIdx)]&PORT_PIN_DYN_DIR_MASK) == PORT_PIN_DYN_DIR_OUT)

/**  brief CHECK_PORT_PIN_DYNDIR_IN(PinIdx) macro:
 **		check if the direction of the pin specified by PinIdx is input
 **		value TRUE: input
 **		value FALSE: output
 **/
#define CHECK_PORT_PIN_DYNDIR_IN(PinIdx)	(PinDynStatusTbl[(PinIdx)]&PORT_PIN_DYN_DIR_MASK == PORT_PIN_DYN_DIR_IN)

/**  brief SET_PORT_PIN_DYNDIR_OUT(PinIdx) macro:
 **		set the direction status of the pin specified by PinIdx to output
 **/
#define SET_PORT_PIN_DYNDIR_OUT(PinIdx)	(PinDynStatusTbl[(PinIdx)] |= PORT_PIN_DYN_DIR_MASK)

/**  brief SET_PORT_PIN_DYNDIR_IN(PinIdx) macro:
 **		set the direction status of the pin specified by PinIdx to input
 **/
#define SET_PORT_PIN_DYNDIR_IN(PinIdx)	(PinDynStatusTbl[(PinIdx)] &= ~PORT_PIN_DYN_DIR_MASK)

/**  brief GET_PORT_PIN_DYNDIR(PinIdx) macro:
 **		get the direction status of the pin specified by PinIdx
 **		value PORT_PIN_DYN_DIR_OUT: output
 **		value PORT_PIN_DYN_DIR_IN: input
 **/
#define GET_PORT_PIN_DYNDIR(PinIdx)		((PinDynStatusTbl[(PinIdx)] & PORT_PIN_DYN_DIR_OUT) ? PORT_PIN_DYN_DIR_OUT : PORT_PIN_DYN_DIR_IN)

/**  brief PORT_PIN_DIR_CHGABLE_MASK macro: the mask flag of the direction-changeable status of a pin
 ** 		bit 1 of PinDynStatusTbl[?]
 ** 		value 0: direction is unchangeable
 ** 		value 1: direction is changeable
 **/
#define PORT_PIN_DIR_CHGABLE_MASK		0x00000002UL

/**  brief CHECK_PORT_PIN_DIR_CHANGEABLE(PinIdx) macro:
 **			check if the direction of the pin specified by PinIdx is changeable
 ** 		value TRUE: direction is changeable
 ** 		value FALSE: direction is unchangeable
 **/
#define CHECK_PORT_PIN_DIR_CHANGEABLE(PinIdx)	((PinDynStatusTbl[(PinIdx)]&PORT_PIN_DIR_CHGABLE_MASK) ? TRUE : FALSE)

/**  brief SET_PORT_PIN_DIR_CHANGEABLE(PinIdx) macro:
 **			set the direction of the pin specified by PinIdx to be changeable
 **/
#define SET_PORT_PIN_DIR_CHANGEABLE(PinIdx)		(PinDynStatusTbl[(PinIdx)] |= PORT_PIN_DIR_CHGABLE_MASK)

/**  brief CLEAR_PORT_PIN_DIR_CHANGEABLE(PinIdx) macro:
 **			clear the direction-changeable status of the pin specified by PinIdx to be changeable
 **/
#define CLEAR_PORT_PIN_DIR_CHANGEABLE(PinIdx)	((PinDynStatusTbl[(PinIdx)] &= (~PORT_PIN_DIR_CHGABLE_MASK))

/**  brief PORT_PIN_IN_NO_PULL macro: the mask flag of none pull function of a input pin
 **/
#define PORT_PIN_IN_NO_PULL 			((uint8)0x0)

/**  brief PORT_PIN_IN_PULL_DOWN macro: the mask flag of pull-down function of a input pin
 **/
#define PORT_PIN_IN_PULL_DOWN 			((uint8)0x1)

/**  brief PORT_PIN_IN_PULL_UP macro: the mask flag of pull-up function of a input pin
 **/
#define PORT_PIN_IN_PULL_UP 			((uint8)0x2)

/**  brief PORT_PIN_OUT_PUSH_PULL macro: the mask flag of push-pull function of a output pin
 **/
#define PORT_PIN_OUT_PUSH_PULL 			((uint8)0x8)

/**  brief PORT_PIN_OUT_OPEN_DRAIN macro: the mask flag of open-drain function of a output pin
 **/
#define PORT_PIN_OUT_OPEN_DRAIN 		((uint8)0xC)

/**  brief PORT_PIN_PC_IN_FUNC_MASK macro:
 **			the mask flag of the function mode among port control coding of a input pin
 ** 		bit 2-3 of PinDynStatusTbl[?]
 ** 		value 0B00:
 ** 		value 0B01:
 ** 		value 0B10:
 ** 		value 0B11:
 **/
#define PORT_PIN_PC_IN_FUNC_MASK		0x000000030UL

/**  brief PORT_PIN_PC_OUT_FUNC_MASK macro:
 ** 		the mask flag of the function mode among port control coding of a output pin
 ** 		bit 6-7 of PinDynStatusTbl[?]
 ** 		value 0B00:	general-purpose output function mode
 ** 		value 0B01: alternate output function 1 mode
 ** 		value 0B10: alternate output function 2 mode
 ** 		value 0B11: alternate output function 3 mode
 **/
#define PORT_PIN_PC_OUT_FUNC_MASK		0x0000000C0UL

/**  brief GET_PORT_PIN_IN_FUNC_MODE(PinIdx) macro:
 **			get the function mode of the input pin specified by PinIdx
 ** 		value 0B00:
 ** 		value 0B01:
 ** 		value 0B10:
 ** 		value 0B11:
 **/
#define GET_PORT_PIN_IN_FUNC_MODE(PinIdx)		((PinDynStatusTbl[(PinIdx)] & PORT_PIN_PC_IN_FUNC_MASK) >> 4)

/**  brief CLEAR_PORT_PIN_IN_FUNC_MODE(PinIdx) macro:
 **			clear the function mode of the input pin specified by PinIdx
 **/
#define CLEAR_PORT_PIN_IN_FUNC_MODE(PinIdx, value)		(PinDynStatusTbl[(PinIdx)] &= (~PORT_PIN_PC_IN_FUNC_MASK))

/**  brief SET_PORT_PIN_IN_FUNC_MODE(PinIdx) macro:
 **			set the function mode of the input pin specified by PinIdx to value
 **/
#define SET_PORT_PIN_IN_FUNC_MODE(PinIdx, value)		(PinDynStatusTbl[(PinIdx)] |= ((uint32)(value) << 4) & PORT_PIN_PC_IN_FUNC_MASK)

/**  brief GET_PORT_PIN_OUT_FUNC_MODE macro:
 **			get the function mode of the output pin specified by PinIdx
 ** 		value 0B00:	general-purpose output function mode
 ** 		value 0B01: alternate output function 1 mode
 ** 		value 0B10: alternate output function 2 mode
 ** 		value 0B11: alternate output function 3 mode
 **/
#define GET_PORT_PIN_OUT_FUNC_MODE(PinIdx)		((PinDynStatusTbl[(PinIdx)] & PORT_PIN_PC_OUT_FUNC_MASK) >> 6)

/**  brief CLEAR_PORT_PIN_OUT_FUNC_MODE(PinIdx) macro:
 **			clear the function mode of the output pin specified by PinIdx
 **/
#define CLEAR_PORT_PIN_OUT_FUNC_MODE(PinIdx)		(PinDynStatusTbl[(PinIdx)] &= (~PORT_PIN_PC_OUT_FUNC_MASK))

/**  brief SET_PORT_PIN_OUT_FUNC_MODE(PinIdx) macro:
 **			set the function mode of the output pin specified by PinIdx to value
 **/
#define SET_PORT_PIN_OUT_FUNC_MODE(PinIdx, value)		(PinDynStatusTbl[(PinIdx)] |= ((uint32)(value) << 6) & PORT_PIN_PC_OUT_FUNC_MASK)

/**  brief GET_PORT_PIN_FUNC_MODE(PinIdx) macro:
 **			get the function mode of the pin specified by PinIdx
 ** 		value 0B00:	general-purpose input/output function mode
 ** 		value 0B01: alternate input/output function 1 mode
 ** 		value 0B10: alternate input/output function 2 mode
 ** 		value 0B11: alternate input/output function 3 mode
 **/
#define GET_PORT_PIN_FUNC_MODE(PinIdx)		(GET_PORT_PIN_DYNDIR(PinIdx) == PORT_PIN_DYN_DIR_OUT ? GET_PORT_PIN_OUT_FUNC_MODE(PinIdx) : GET_PORT_PIN_IN_FUNC_MODE(PinIdx) )

/**  brief CHECK_PORT_PIN_FUNC_GPIO(PinIdx) macro:
 **			check if the function mode of the pin specified by PinIdx is general-purpose input/output mode
 **			value TRUE: the function mode of the pin specified by PinIdx is general-purpose input/output mode
 **			value FALSE: the function mode of the pin specified by PinIdx is not general-purpose input/output mode
 **/
#define CHECK_PORT_PIN_FUNC_GPIO(PinIdx)		(GET_PORT_PIN_FUNC_MODE(PinIdx) == 0 ? TRUE : FALSE)

/**  brief PORT_PIN_PC_IN_MASK macro: the mask flag of the port control coding of a input pin
 ** 		bit 2-5 of PinDynStatusTbl[?]
 **			value 0B0x00: no input pull device connected
 **			value 0B0x01: input pull-down device connected
 **			value 0B0x10: input pull-up device connected
 **			value 0B0x11: no input pull device connected
 **/
#define PORT_PIN_PC_IN_MASK				0x0000003CUL

/**  brief PORT_PIN_PC_OUT_MASK macro: the mask flag of the port control coding of a output pin
 ** 		bit 6-9 of PinDynStatusTbl[?]
 **			value 0B1000: general-purpose output with push-pull selected
 **			value 0B1001: alternate output function 1 with push-pull selected
 **			value 0B1010: alternate output function 2 with push-pull selected
 **			value 0B1011: alternate output function 3 with push-pull selected
 **			value 0B1100: general-purpose output with open-drain selected
 **			value 0B1101: alternate output function 1 with open-drain selected
 **			value 0B1110: alternate output function 2 with open-drain selected
 **			value 0B1111: alternate output function 3 with open-drain selected
 **/
#define PORT_PIN_PC_OUT_MASK			0x000003C0UL

/**  brief GET_PORT_PIN_PC_IN(PinIdx) macro:
 **			get the the port control coding of the input pin specified by PinIdx
 **			value 0B0x00: no input pull device connected
 **			value 0B0x01: input pull-down device connected
 **			value 0B0x10: input pull-up device connected
 **			value 0B0x11: no input pull device connected
 **/
#define GET_PORT_PIN_PC_IN(PinIdx)			((PinDynStatusTbl[(PinIdx)] & PORT_PIN_PC_IN_MASK) >> 2)

/**  brief PORT_PIN_PC_OUT_MASK macro:
 ** 		get the the port control coding of the output pin specified by PinIdx
 **			value 0B1000: general-purpose output with push-pull selected
 **			value 0B1001: alternate output function 1 with push-pull selected
 **			value 0B1010: alternate output function 2 with push-pull selected
 **			value 0B1011: alternate output function 3 with push-pull selected
 **			value 0B1100: general-purpose output with open-drain selected
 **			value 0B1101: alternate output function 1 with open-drain selected
 **			value 0B1110: alternate output function 2 with open-drain selected
 **			value 0B1111: alternate output function 3 with open-drain selected
 **/
#define GET_PORT_PIN_PC_OUT(PinIdx)			((PinDynStatusTbl[(PinIdx)] & PORT_PIN_PC_OUT_MASK) >> 6)

/**  brief SET_PORT_PIN_PC_IN(PinIdx, value) macro:
 ** 		set the the port control coding of the input pin to value
 **/
#define SET_PORT_PIN_PC_IN(PinIdx, value)			(PinDynStatusTbl[(PinIdx)] |= ((uint32)(value) << 2) & PORT_PIN_PC_IN_MASK)

/**  brief SET_PORT_PIN_PC_OUT(PinIdx, value) macro:
 ** 		set the the port control coding of the output pin to value
 **/
#define SET_PORT_PIN_PC_OUT(PinIdx, value)			(PinDynStatusTbl[(PinIdx)] |= ((uint32)(value) << 6) & PORT_PIN_PC_OUT_MASK)

/**  brief PORT_PIN_PD_OUT_MASK macro:
 **			the mask flag of the pad driver mode coding of a output pin
 **			bit 10-12 of PinDynStatusTbl[?]
 **			value 0B000: A1 Medium driver selected / A2 Strong driver, sharp edge selected
 **			value 0B001: A1 Weak driver selected / A2 Strong driver, medium edge selected
 **			value 0B010: A2 Strong driver, soft edge selected
 **			value 0B011: A2 Weak driver selected
 **			value 0B100: A2 Medium driver selected
 **			value 0B101: A2 Medium driver selected
 **			value 0B110: A2 Medium driver selected
 **			value 0B111: A2 Weak driver selected
 **/
#define PORT_PIN_PD_OUT_MASK			0x00001C00UL

/**  brief GET_PORT_PIN_PD_OUT(PinIdx) macro:
 **			get the pad driver mode coding of a output pin specified by PinIdx
 **			value 0B000: A1 Medium driver selected / A2 Strong driver, sharp edge selected
 **			value 0B001: A1 Weak driver selected / A2 Strong driver, medium edge selected
 **			value 0B010: A2 Strong driver, soft edge selected
 **			value 0B011: A2 Weak driver selected
 **			value 0B100: A2 Medium driver selected
 **			value 0B101: A2 Medium driver selected
 **			value 0B110: A2 Medium driver selected
 **			value 0B111: A2 Weak driver selected
 **/
#define GET_PORT_PIN_PD_OUT(PinIdx)			((PinDynStatusTbl[(PinIdx)] & PORT_PIN_PD_OUT_MASK) >> 10)

/**  brief CLEAR_PORT_PIN_PD_OUT(PinIdx) macro:
 **			clear the pad driver mode coding of a output pin specified by PinIdx
 **/
#define CLEAR_PORT_PIN_PD_OUT(PinIdx)			(PinDynStatusTbl[(PinIdx)] &= ~PORT_PIN_PD_OUT_MASK)

/**  brief SET_PORT_PIN_PD_OUT(PinIdx, value) macro:
 **			set the pad driver mode coding of a output pin specified by PinIdx to value
 **/
#define SET_PORT_PIN_PD_OUT(PinIdx, value)			(PinDynStatusTbl[(PinIdx)] |= ((uint32)(value) << 10) & PORT_PIN_PD_OUT_MASK)

/**	brief PORT_PIN_NO_INPUT_PULL_DEVICE macro:
 **			there is no input pull device connected with this pin.
 **/
#define PORT_PIN_NO_INPUT_PULL_DEVICE	((uint8)0)

/**	brief PORT_PIN_INPUT_PULL_DOWN_DEVICE macro:
 **			there is an input pull-down device connected with this pin.
 **/
#define PORT_PIN_INPUT_PULL_DOWN_DEVICE	((uint8)1)

/**	brief PORT_PIN_INPUT_PULL_UP_DEVICE macro:
 **			there is  an input pull-up device connected with this pin.
 **			it's the default status of the input characteristics of the pin.
 **/
#define	PORT_PIN_INPUT_PULL_UP_DEVICE	((uint8)2)


/**	brief PORT_PIN_PUSH_PULL macro:
 **			the pin's output is push-pull.
 **/
#define PORT_PIN_PUSH_PULL	((uint8)0)

/**	brief PORT_PIN_OPEN_DRAIN macro:
 **			the pin's output is open-drain.
 **/
#define PORT_PIN_OPEN_DRAIN	((uint8)1)

/**	brief PORT_PIN_EM_STOP_EN_MASK macro:
 **			the pin's switch statues of the function of emergence stop.
 **/
#define PORT_PIN_EM_STOP_EN_MASK	0x00002000UL

/**	brief SET_PORT_PIN_EM_STOP_EN(PinIdx) macro:
 **			enable the pin's switch statues of the function of emergence stop.
 **/
#define SET_PORT_PIN_EM_STOP_EN(PinIdx)			(PinDynStatusTbl[(PinIdx)] |= (uint32)PORT_PIN_EM_STOP_EN_MASK)

/**	brief RESET_PORT_PIN_EM_STOP_EN(PinIdx) macro:
 **			disable the pin's switch statues of the function of emergence stop.
 **/
#define RESET_PORT_PIN_EM_STOP_EN(PinIdx)			(PinDynStatusTbl[(PinIdx)] &= ~((uint32)PORT_PIN_EM_STOP_EN_MASK))

/**	brief CHECK_PORT_PIN_EM_STOP_EN(PinIdx) macro:
 **			check the pin's switch statues of the function of emergence stop.
 **/
#define CHECK_PORT_PIN_EM_STOP_EN(PinIdx)			((PinDynStatusTbl[(PinIdx)] & (uint32)PORT_PIN_EM_STOP_EN_MASK) >> 13)

/**	brief PORT_PIN_EM_STOP_LEVEL_MASK macro:
 **			the pin's level of the function of emergence stop.
 **/
#define PORT_PIN_EM_STOP_LEVEL_MASK	0x00004000UL


/**	brief SET_PORT_PIN_EM_STOP_EN macro:
 **			set the pin's output level of the function of emergence stop.
 **/
#define SET_PORT_PIN_EM_STOP_LEVEL(PinIdx)			(PinDynStatusTbl[(PinIdx)] |= (uint32)PORT_PIN_EM_STOP_LEVEL_MASK)

/**	brief RESET_PORT_PIN_EM_STOP_LEVEL(PinIdx) macro:
 **			reset the pin's output level of the function of emergence stop.
 **/
#define RESET_PORT_PIN_EM_STOP_LEVEL(PinIdx)			(PinDynStatusTbl[(PinIdx)] &= ~((uint32)PORT_PIN_EM_STOP_LEVEL_MASK))

/**	brief CHECK_PORT_PIN_EM_STOP_LEVEL(PinIdx) macro:
 **			check the pin's output level of the function of emergence stop.
 **/
#define CHECK_PORT_PIN_EM_STOP_LEVEL(PinIdx)			((PinDynStatusTbl[(PinIdx)] & (uint32)PORT_PIN_EM_STOP_LEVEL_MASK) >> 14)

/**	brief PORT_PIN_MODE_CHANGEABLE_MASK macro:
 **			the mask of the pin's switch of mode changeable.
 **/
#define PORT_PIN_MODE_CHANGEABLE_MASK	0x00008000UL

/**	brief SET_PORT_PIN_MODE_CHANGEABLE(PinIdx) macro:
 **			set the pin's switch of mode changeable.
 **/
#define SET_PORT_PIN_MODE_CHANGEABLE(PinIdx)			(PinDynStatusTbl[(PinIdx)] |= (uint32)PORT_PIN_MODE_CHANGEABLE_MASK)

/**	brief CHECK_PORT_PIN_MODE_CHANGEABLE(PinIdx) macro:
 **			check the pin's switch of mode changeable.
 **/
#define	CHECK_PORT_PIN_MODE_CHANGEABLE(PinIdx)		((PinDynStatusTbl[(PinIdx)] & (uint32)PORT_PIN_MODE_CHANGEABLE_MASK) >> 15)

/*******************************************************************
| external declarations:
| function prototypes (scope: module-exported)
| extern variable (scope: module-exported)
|------------------------------------------------------------------*/
extern Port_ConfigTypeRef Port_CurCfg;
extern const uint8 UsrPIdToPdIdxMapTbl[];
extern const PortPinIdType UsrPIdToHwPIdMapTbl[];
extern uint32 volatile PinDynStatusTbl[];

/*******************************************************************
| function prototypes (scope: module-local)
|------------------------------------------------------------------*/
void Port_Hw_Init(uint8 index, Port_ConfigTypeRef tmpPortCfg);

void Port_Hw_SetPinDir(uint8 index, Port_PinDirectionType Direction);

void Port_Hw_SetPinMode(uint8 index, Port_PinModeType Mode);

void Port_Hw_Update_PcValue(uint8 index, Port_ConfigTypeRef tmpPortCfg);

#endif /* PORT_HW_H_ */
